﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace ArmoryAPI
{
    /// <summary>
    /// Represents a World of Warcraft character providing basic information such as level, achievement points etc.
    /// </summary>
    public class Character
    {
        #region Members
            private string _name;
            private string _realm;
            private Int16 _class;
            private Int16 _race;
            private bool _gender;
            private Int16 _level;
            private Int32 _achievementPoints;
            private string _thumbnail;
            private DateTime _lastModified;
            private bool _expired;
            private BattleNetRegion _region;

            /* Extra data */
            private Guild _guild;
            private ICollection<UnlockedAchievement> _achievements;
            private ICollection<Title> _titles;
        #endregion

        #region Properties

            /// <summary>
            /// The name of the character
            /// </summary>
            public string Name
            {
                get
                {
                    return _name;
                }
            }

            /// <summary>
            /// The name of the realm the character is located on
            /// </summary>
            public string Realm
            {
                get
                {
                    return _realm;
                }
            }

            /// <summary>
            /// The class of the character in integer form
            /// </summary>
            internal Int16 ClassID
            {
                get
                {
                    return _class;
                }
            }

            /// <summary>
            /// The class of the character
            /// </summary>
            public string Class
            {
                // This needs storing in the database at some point...
                get
                {
                    switch (_class)
                    {
                        case 1: return "Warrior";
                        case 2: return "Paladin";
                        case 3: return "Hunter";
                        case 4: return "Rogue";
                        case 5: return "Priest";
                        case 6: return "Death Knight";
                        case 7: return "Shaman";
                        case 8: return "Mage";
                        case 9: return "Warlock"; 
                        case 11: return "Druid";
                        default: return String.Empty;
                    }
                }
            }

            /// <summary>
            /// The race of the character in integer form
            /// </summary>
            internal Int16 RaceID
            {
                get
                {
                    return _race;
                }
            }

            /// <summary>
            /// The race of the character
            /// </summary>
            public string Race
            {
                get
                {
                    switch (_race)
                    {
                        case 1: return "Human";
                        case 2: return "Orc";
                        case 3: return "Dwarf";
                        case 4: return "Night Elf";
                        case 5: return "Undead";
                        case 6 : return "Tauren";
                        case 7 : return "Gnome";
                        case 8 : return "Troll";
                        case 9 : return "Goblin";
                        case 10: return "Blood Elf";
                        case 11: return "Draenei";
                        case 22: return "Worgen";
                        default: return string.Empty;
                    }
                }
            }

            /// <summary>
            /// The gender of the character in bit form, false represents male, true represents female
            /// </summary>
            internal bool GenderBitFlag
            {
                get
                {
                    return _gender;
                }
            }

            /// <summary>
            /// The level of the character
            /// </summary>
            public Int16 Level
            {
                get
                {
                    return _level;
                }
            }

            /// <summary>
            /// The total number of achievement points earned by the character
            /// </summary>
            public Int32 AchievementPoints
            {
                get
                {
                    return _achievementPoints;
                }
            }

            /// <summary>
            /// Indiciates whether or not the data cache has expired and needs refreshing
            /// </summary>
            public bool HasExpired
            {
                get
                {
                    return _expired;
                }
            }

            /// <summary>
            /// The date and time the data was last updated by Battle.net
            /// </summary>
            public DateTime LastModified
            {
                get
                {
                    return _lastModified;
                }
            }

            /// <summary>
            /// The guild the character is a member of
            /// </summary>
            public Guild Guild
            {
                get
                {
                    return _guild;
                }
                internal set
                {
                    _guild = value;
                }
            }

            /// <summary>
            /// A collection of the achievments the character has unlocked
            /// </summary>
            public ICollection<UnlockedAchievement> Achievements
            {
                get
                {
                    return _achievements;
                }
                internal set
                {
                    _achievements = value;
                }
            }

            /// <summary>
            /// A collection of the titles the character has unlocked
            /// </summary>
            public ICollection<Title> Titles
            {
                get
                {
                    return _titles;
                }
                internal set
                {
                    _titles = value;
                }
            }

            /// <summary>
            /// The character's full thumbnail URL
            /// </summary>
            public string Thumbnail
            {
                get
                {
                    return String.Format("http://{0}/static-render/{1}/{2}", Armory.GetAPIBase(_region), Armory.GetRegionAbbreviation(_region), _thumbnail);
                }
            }

            internal string RelativeThumbnail
            {
                get
                {
                    return _thumbnail;
                }
            }

        #endregion

        #region Instance Methods

            /// <summary>
            /// Parses the guild token from the Battle.net character API into a guild object
            /// </summary>
            /// <param name="data">The guild token encapsualted in a JToken</param>
            internal void ParseGuildData(JToken data)
            {
                try
                {
                    _guild = new Guild( (String)data["name"], 
                                        (String)data["realm"], 
                                        (Int16)data["level"], 
                                        (Int16)data["members"], 
                                        (Int32)data["achievementPoints"]);

                }
                catch
                {
                    _guild = null;
                }
            }

            /// <summary>
            /// Parses the achievements token from the Battle.net character API into a Collection of Achievements
            /// </summary>
            /// <param name="data">The achievements token encapsulated in a JToken</param>
            /// <param name="request">The WebRequest or DatabaseRequest object that will be used to inflate the achievement data</param>
            internal void ParseAchievementData(JToken data, Object request)
            {
                if ((data["achievementsCompleted"] != null) && (data["achievementsCompletedTimestamp"] != null))
                {
                    JToken achievementsCompleted = data["achievementsCompleted"];
                    JToken achievementsCompletedTimestamp = data["achievementsCompletedTimestamp"];
                    ICollection<Achievement> achievements = null;
                    _achievements = new List<UnlockedAchievement>();

                    // If we are inflating using the API then we will do the parsing in this method to prevent
                    // multiple requests to the API as otherwise we may reach the threshold quite easily
                    if (request.GetType() == typeof(WebRequest))
                    {
                        achievements = ((WebRequest)request).GetAllAchievements();
                    }

                    for (int i = 0; i < achievementsCompleted.Count(); i++)
                    {
                        int achievementID = -1;
                        long timestamp = -1;

                        achievementID = (int) achievementsCompleted.ElementAt(i);
                        timestamp = (long) achievementsCompletedTimestamp.ElementAt(i);

                        if ((achievementID > -1) && (timestamp > -1))
                        {
                            if (request.GetType() == typeof(WebRequest))
                            {
                                foreach (Achievement achievement in achievements)
                                {
                                    if (achievement.ID == achievementID)
                                    {
                                        _achievements.Add(new UnlockedAchievement(achievement, timestamp));
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                _achievements.Add(new UnlockedAchievement(((DatabaseRequest)request).GetAchievementByID(achievementID), timestamp));
                            }
                        }
                    }
                }
            }

            /// <summary>
            /// Parses the titles token from the Battle.net character API into a collection of Titles
            /// </summary>
            /// <param name="data">The titles token encapsulated in a JToken</param>
            internal void ParseTitleData(JToken data)
            {
                _titles = new List<Title>();

                foreach (JToken title in data.Children())
                {
                    if (title["name"] != null)
                    {
                        _titles.Add(new Title(_name, (String)title["name"]));
                    }
                }
            }

        #endregion

        #region Constructors

            /// <summary>
            /// Constructs an empty Character
            /// </summary>
            public Character()
            {
                _name = String.Empty;
                _realm = String.Empty;
                _class = -1;
                _race = -1;
                _gender = false;
                _level = -1;
                _achievementPoints = -1;
                _thumbnail = String.Empty;
                _lastModified = DateTime.Now;
                _expired = false;
                _guild = new Guild();
                _achievements = new List<UnlockedAchievement>();
                _titles = new List<Title>();
            }

            internal Character(string name, string realm, Int16 classID, Int16 race, bool gender, Int16 level, Int32 achievementPoints, DateTime lastModified, bool hasExpired, string thumbnail, BattleNetRegion region)
            {
                _name = name;
                _realm = realm;
                _class = classID;
                _race = race;
                _gender = gender;
                _level = level;
                _achievementPoints = achievementPoints;
                _lastModified = lastModified;
                _expired = hasExpired;
                _achievements = new List<UnlockedAchievement>();
                _titles = new List<Title>();
                _region = region;
                _thumbnail = thumbnail;
            }

        #endregion
    }
}
